package gao.xiaolei.service;

import javax.annotation.Resource;
import gao.xiaolei.exception.AttachedException;
import gao.xiaolei.exception.AuthException;
import gao.xiaolei.exception.DevManException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import xiaolei.gao.Image.ImageInterface;
import gao.xiaolei.dao.TestProjectDao;
import gao.xiaolei.dao.TestSystemAttachedDao;
import gao.xiaolei.dao.TestSystemDao;
import gao.xiaolei.dto.TestSystemDto;
import gao.xiaolei.entity.TestSystem;
import gao.xiaolei.entity.TestSystemAttached;
import xiaolei.gao.file.FileInterface;
import gao.xiaolei.util.Md5;
import gao.xiaolei.util.ServiceName;
import gao.xiaolei.util.UuidUtil;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.*;

@Service("TestSystemService")
public class TestSystemService {

    @Resource(name = "FileInterface")
    private FileInterface fileInterface;

    @Resource(name = "ImageInterface")
    private ImageInterface imageInterface;

    @Autowired
    private RestTemplate restTemplate;

    @Resource(name = "TestSystemDao")
    private TestSystemDao testSystemDao;

    @Resource(name = "TestSystemAttachedDao")
    private TestSystemAttachedDao testSystemAttachedDao;

    @Resource(name = "TestProjectDao")
    TestProjectDao testProjectDao;

    @Transactional
    //添加系统
    public void addTestSystem(String id, String name, int type, String describe, String addMan, String devMan, List<TestSystemAttached> attachedList, MultipartFile[] attachedFiles) throws IOException {
        if (attachedList.size() != attachedFiles.length)
            throw new AttachedException("文件列表数量为"
                    .concat(String.valueOf(attachedList.size()))
                    .concat(",上传文件数量为")
                    .concat(String.valueOf(attachedFiles.length))
                    .concat(",数量不符"));
        if (type == 0 && devMan == null)
            throw new DevManException("真实项目的开发者不能为空！");
        LocalDateTime nowDate = LocalDateTime.now();
        testSystemDao.save(new TestSystem(id, name, type, describe, addMan, devMan, nowDate, nowDate));
        int i, length;
        List<String> hashOrUuidList = new LinkedList<>();//用于储存文件的uuid或者hash码,因为要保证文件操作在最后才做
        String hashOrUuid = null;
        for (i = 0, length = attachedList.size(); i < length; i++) {
            if (attachedList.get(i).getType() == 0)
                hashOrUuid = Md5.md5HashCode32(attachedFiles[i].getBytes());//图片则自己生成Hash码
            else
                hashOrUuid = UuidUtil.get32Uuid();
            hashOrUuidList.add(hashOrUuid);
            attachedList.get(i).setSize((int) attachedFiles[i].getSize() / 1000);//保存附件的大小
            attachedList.get(i).setFileUuid(hashOrUuid);//保存附件的文件名
            testSystemAttachedDao.save(attachedList.get(i));
        }
        for (i = 0, length = attachedList.size(); i < length; i++) {//最后再去保存文件，因为文件操作无法回退
            if (attachedList.get(i).getType() == 0)
                imageInterface.imageUploadWithDefineHashCode(attachedFiles[i], hashOrUuidList.get(i));
            else
                fileInterface.fileUpload(attachedFiles[i], hashOrUuidList.get(i));
        }
    }

    @Transactional
    //修改系统信息
    public void updateTestSystem(String id, String name, int type, String describe, String addMan, String devMan, List<TestSystemAttached> newAttachedList, MultipartFile[] attachedFiles, String currentUserId) throws IOException {
        if (!testSystemDao.getAddMan(id).orElse("无").equals(currentUserId))//如果不是自己添加的项目不能修改
            throw new AuthException("该系统（".concat(id).concat(")你没有权限修改！"));
        List<TestSystemAttached> oldAttached = testSystemAttachedDao.findAllBySystem(id);//先将旧的系统附件查出来
        Map<String, Integer> willDeleteFile = new HashMap<>();//记录等一下要删除的文件Uuid和文件类型
        Map<String, Integer> willUploadFile = new LinkedHashMap<>();//记录等一下要上传的文件Uuid和文件类型，为了实现插入顺序和遍历顺序一致，所以使用LinkedHashMap
        boolean isDelete, isAdd;
        String oldAttaId = null, newAttaId = null;
        int i, j, length, length2;
        for (i = 0, length = oldAttached.size(); i < length; i++) {//比较旧附件列表是否有新附件列表所没有的
            isDelete = true;
            oldAttaId = oldAttached.get(i).getId();
            for (j = 0, length2 = newAttachedList.size(); j < length2; j++) {
                if (oldAttaId.equals(newAttachedList.get(j).getId())) {
                    isDelete = false;//如果新列表里面也有的话说明就不要删除
                    break;
                }
            }
            if (isDelete) {
                testSystemAttachedDao.deleteById(oldAttaId);
                willDeleteFile.put(oldAttached.get(i).getFileUuid(), oldAttached.get(i).getType());
            }
        }
        int addCount = -1;//记录现在是第几个新添加的文件
        for (i = 0, length = newAttachedList.size(); i < length; i++) {//查看新附件列表里面是否有旧列表里没有的
            isAdd = true;
            newAttaId = newAttachedList.get(i).getId();
            for (j = 0, length2 = oldAttached.size(); j < length2; j++) {
                if (newAttaId.equals(oldAttached.get(j).getId())) {
                    isAdd = false;//如果旧的里面也有的话说明就不用添加
                    break;
                }
            }
            if (isAdd) {
                addCount++;
                String hashOrUuid = null;//先统一生成新文件的文件名
                if (newAttachedList.get(i).getType() == 0)
                    hashOrUuid = Md5.md5HashCode32(attachedFiles[addCount].getBytes());//图片则自己生成Hash码
                else
                    hashOrUuid = UuidUtil.get32Uuid();
                newAttachedList.get(i).setSize((int) attachedFiles[addCount].getSize() / 1000);//保存附件的大小
                newAttachedList.get(i).setFileUuid(hashOrUuid);//保存附件的文件名
                testSystemAttachedDao.save(newAttachedList.get(i));
                willUploadFile.put(hashOrUuid, newAttachedList.get(i).getType());
            }
        }
        if (willUploadFile.size() != attachedFiles.length)//比较预计上传文件和实际上传文件数量是否相同
            throw new AttachedException("新添加的文件数量为"
                    .concat(String.valueOf(willUploadFile.size()))
                    .concat(",上传文件数量为")
                    .concat(String.valueOf(attachedFiles.length))
                    .concat(",数量不符"));
        TestSystem oldSystem = testSystemDao.findById(id).orElseThrow(() -> new IllegalArgumentException("该系统"
                .concat(id)
                .concat("不存在！")));
        testSystemDao.save(new TestSystem(id, name, type, describe, oldSystem.getAddMan(), oldSystem.getDevMan(), oldSystem.getCreateDate(), LocalDateTime.now()));//保存系统信息
        for (Map.Entry<String, Integer> wd : willDeleteFile.entrySet()) {//依次调用文件服务去删除文件
            if (wd.getValue() == 0)
                imageInterface.imageDelete(wd.getKey());
            else
                fileInterface.fileDelete(wd.getKey());
        }
        i = 0;
        for (Map.Entry<String, Integer> wu : willUploadFile.entrySet()) {//依次调用文件服务去上传文件
            if (wu.getValue() == 0)
                imageInterface.imageUploadWithDefineHashCode(attachedFiles[i++], wu.getKey());
            else
                fileInterface.fileUpload(attachedFiles[i++], wu.getKey());
        }
    }

    @Transactional(readOnly = true)
    //获取系统的详细信息
    public TestSystemDto getSystemDetail(String id) {
        return privateGetSystemDetail(id);
    }

    @Transactional(readOnly = true)
    //根据project获取对应system的详细信息
    public TestSystemDto getSystemDetailOfProject(String projectId) {
        String systemId = testProjectDao.getSystem(projectId).orElseThrow(() -> new IllegalArgumentException("该测试项目"
                .concat("(")
                .concat(projectId)
                .concat(")").concat("不存在")));
        return privateGetSystemDetail(systemId);
    }

    @Transactional(readOnly = true)
    //获取系统列表
    public List<TestSystem> getSystemList() {
        List<TestSystem> result = testSystemDao.findAll();
        List<TestSystem> out = new ArrayList<>(result.size());
        String addManName = null;
        for (int i = 0, length = result.size(); i < length; i++) {//获取添加人的昵称
            addManName = restTemplate.getForObject(ServiceName.AUTH_SERVICE.getServiceName().concat("/user/realName/").concat(result.get(i).getAddMan()), String.class);
            out.add(new TestSystem(result.get(i), addManName));
        }
        return out;
    }

    @Transactional(readOnly = true)
    //下载附件
    public ResponseEntity<byte[]> downloadAttached(String attachedId) throws UnsupportedEncodingException {
        TestSystemAttached attached = testSystemAttachedDao.findById(attachedId).orElseThrow(() -> (new IllegalArgumentException("附件"
                .concat(attachedId)
                .concat("不存在！"))));
        MultiValueMap<String, String> header = new LinkedMultiValueMap<>(1);
        header.add("content-disposition", "attachment;filename=" + URLEncoder.encode(attached.getName(), "UTF-8"));
        byte[] fileByte = null;
        if (attached.getType() == 0)
            fileByte = imageInterface.getImage(attached.getFileUuid());
        else
            fileByte = fileInterface.getFile(attached.getFileUuid());
        return new ResponseEntity<byte[]>(fileByte, header, HttpStatus.OK);
    }

    @Transactional
    //删除系统
    public void deleteTestSystem(String id) {
        if (testSystemDao.existsById(id))
            testSystemDao.deleteById(id);
        else
            throw new IllegalArgumentException("该系统"
                    .concat(id)
                    .concat("不存在！"));
        List<TestSystemAttached> attachedList = testSystemAttachedDao.findAllBySystem(id);
        Map<String, Integer> willDeleteFile = new HashMap<>();//记录等一下要删除的文件Uuid和文件类型
        for (int i = 0, length = attachedList.size(); i < length; i++) {
            willDeleteFile.put(attachedList.get(i).getFileUuid(), attachedList.get(i).getType());
            testSystemAttachedDao.delete(attachedList.get(i));
        }
        for (Map.Entry<String, Integer> wd : willDeleteFile.entrySet()) {//依次调用文件服务去删除文件
            if (wd.getValue() == 0)
                imageInterface.imageDelete(wd.getKey());
            else
                fileInterface.fileDelete(wd.getKey());
        }
    }

    // 获取系统名称
    public String getSystemName(String id) {
        return testSystemDao.getSystemName(id).orElseThrow(() -> new IllegalArgumentException("不存在此被测试项目！"));
    }

    private TestSystemDto privateGetSystemDetail(String systemId) {
        TestSystem testSystem = testSystemDao.findById(systemId).orElseThrow(() -> new IllegalArgumentException("该系统"
                .concat(systemId)
                .concat("不存在！")));
        TestSystem outSystem = new TestSystem();
        BeanUtils.copyProperties(testSystem, outSystem);
        String addMan = null, devMan = null;
        if (outSystem.getAddMan() != null)
            addMan = restTemplate.getForObject(ServiceName.AUTH_SERVICE.getServiceName().concat("/user/realName/").concat(outSystem.getAddMan()), String.class);
        if (outSystem.getDevMan() != null)
            devMan = restTemplate.getForObject(ServiceName.AUTH_SERVICE.getServiceName().concat("/user/realName/").concat(outSystem.getDevMan()), String.class);
        outSystem.setAddManName(addMan);
        outSystem.setDevMan(devMan);
        List<TestSystemAttached> atta = testSystemAttachedDao.findAllBySystem(systemId);
        return new TestSystemDto(outSystem, atta);
    }

}
